package advanced.thread;


/**
 * 可重入锁: 锁可以延续使用
 */
public class L16 {
    //    Lock lock = new Lock();//模拟不可重入锁
    RentrentLock lock = new RentrentLock();//模拟可重入锁

    public static void main(String[] args) {
        L16 l16 = new L16();
        l16.a();
        l16.doSomething();

    }

    public void test() {
        //第一次获得锁
        synchronized (this) {
            while (true) {
                //第二次获得同样的额锁
                synchronized (this) {

                    System.out.println("ReentrantLck!");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 模拟二次获取锁, 但是不可重入,导致一直等待
     */
    public void doSomething() {
        lock.lock();
        System.out.println("doSomething + :" + lock.getHoldCount());
        // TODO: 2019/7/1
        lock.unLock();
        System.out.println("doSomething - :" + lock.getHoldCount());
    }

    public void a() {
        lock.lock();
        System.out.println("a + :" + lock.getHoldCount());
        doSomething();
        lock.unLock();
        System.out.println("a - :" + lock.getHoldCount());
    }
}

/**
 * 模拟不可重入锁: 锁不可以延续使用
 */
class Lock {
    //是否使用
    private boolean isLocaked = false;

    //使用锁
    public synchronized void lock() {
        while (isLocaked) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocaked = true;
    }

    //释放锁
    public synchronized void unLock() {
        notify();
        isLocaked = false;
    }
}

/**
 * 模拟重入锁
 */
class RentrentLock {
    //是否使用
    private boolean isLocaked = false;
    private Thread lockedBy = null;//存储由谁锁了
    private int holdCount = 0; //当前线程使用了几次锁,  等于0时解开锁,让其他线程使用

    //使用锁
    public synchronized void lock() {
        Thread t = Thread.currentThread();
        while (isLocaked && lockedBy != t) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocaked = true;
        lockedBy = t;
        holdCount++;
    }

    //释放锁
    public synchronized void unLock() {
        if (Thread.currentThread() == lockedBy) {
            holdCount--;
            if (holdCount == 0) {
                //解除当前线程的锁定, 让其他线程可以使用
                notify();
                isLocaked = false;
                lockedBy = null;
            }
        }

    }

    public int getHoldCount() {
        return holdCount;
    }
}
